In [1]:
!mkdir -p ~/agave

%cd ~/agave

!pip3 install --upgrade setvar

import re
import os
import sys
from setvar import *
from time import sleep

# This cell enables inline plotting in the notebook
%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
!auth-tokens-refresh


/home/jovyan/agave
Requirement already up-to-date: setvar in /opt/conda/lib/python3.6/site-packages
Token for agave.prod:stevenrbrandt successfully refreshed and cached for 14400 seconds
fcb7c1e28e99ae172d8f62bbbbf95ed4

Adding dynamic inputs

Let's update our previous input file with some dynamic behavior. Here we replace a couple of the variables, AMP and WID with placeholders. We'll also rename it with a .tpl extension so we're not confused out its purpose.


In [2]:
writefile("funwave-input.tpl","""
!INPUT FILE FOR FUNWAVE_TVD
  ! NOTE: all input parameter are capital sensitive
  ! --------------------TITLE-------------------------------------
  ! title only for log file
TITLE = VESSEL
  ! -------------------HOT START---------------------------------
HOT_START = F
FileNumber_HOTSTART = 1
  ! -------------------PARALLEL INFO-----------------------------
  ! 
  !    PX,PY - processor numbers in X and Y
  !    NOTE: make sure consistency with mpirun -np n (px*py)
  !    
PX = 2
PY = 1
  ! --------------------DEPTH-------------------------------------
  ! Depth types, DEPTH_TYPE=DATA: from depth file
  !              DEPTH_TYPE=FLAT: idealized flat, need depth_flat
  !              DEPTH_TYPE=SLOPE: idealized slope, 
  !                                 need slope,SLP starting point, Xslp
  !                                 and depth_flat
DEPTH_TYPE = FLAT
DEPTH_FLAT = 10.0
  ! -------------------PRINT---------------------------------
  ! PRINT*,
  ! result folder
RESULT_FOLDER = output/

  ! ------------------DIMENSION-----------------------------
  ! global grid dimension
Mglob = 500
Nglob = 100

  ! ----------------- TIME----------------------------------
  ! time: total computational time/ plot time / screen interval 
  ! all in seconds
TOTAL_TIME = 4.0
PLOT_INTV = 1.0
PLOT_INTV_STATION = 50000.0
SCREEN_INTV = 1.0
HOTSTART_INTV = 360000000000.0

WAVEMAKER = INI_GAU
AMP = %AMP%
Xc = 250.0
Yc = 50.0
WID = %WID%

  ! -----------------GRID----------------------------------
  ! if use spherical grid, in decimal degrees
  ! cartesian grid sizes
DX = 1.0
DY = 1.0
  ! ----------------SHIP WAKES ----------------------------
VESSEL_FOLDER = ./
NumVessel = 2
  ! -----------------OUTPUT-----------------------------
ETA = T
U = T
V = T
""")


Writing file `funwave-input.tpl'

Smarter wrapper templates

Our previous wrapper script was as simple as it gets, blindly calling any command it was given. Here we will add some logic restrict it to only run our funwave application with required variables, print out our runtime variables, and properly exit if anything goes wrong.


In [3]:
writefile("funwave-wrapper.txt","""
#!/bin/bash
# This is a generic wrapper script for checking the runtime environment
# of a job and verifying the runtime template variable values
set +x

date

# print out the agave runtiem variables
echo "##################################################"
echo "# Agave Job Runtime Variables "
echo "##################################################"
echo "\n"
echo 'AGAVE_JOB_NAME="\${AGAVE_JOB_NAME}"'
echo 'AGAVE_JOB_ID="\${AGAVE_JOB_ID}"'
echo 'AGAVE_JOB_APP_ID="\${AGAVE_JOB_APP_ID}"'
echo 'AGAVE_JOB_EXECUTION_SYSTEM="\${AGAVE_JOB_EXECUTION_SYSTEM}"'
echo 'AGAVE_JOB_BATCH_QUEUE="\${AGAVE_JOB_BATCH_QUEUE}"'
echo 'AGAVE_JOB_SUBMIT_TIME="\${AGAVE_JOB_SUBMIT_TIME}"'
echo 'AGAVE_JOB_ARCHIVE_SYSTEM="\${AGAVE_JOB_ARCHIVE_SYSTEM}"'
echo 'AGAVE_JOB_ARCHIVE_PATH="\${AGAVE_JOB_ARCHIVE_PATH}"'
echo 'AGAVE_JOB_NODE_COUNT="\${AGAVE_JOB_NODE_COUNT}"'
echo 'AGAVE_JOB_PROCESSORS_PER_NODE="\${AGAVE_JOB_PROCESSORS_PER_NODE}"'
echo 'AGAVE_JOB_MEMORY_PER_NODE="\${AGAVE_JOB_MEMORY_PER_NODE}"'
echo 'AGAVE_JOB_ARCHIVE_URL="\${AGAVE_JOB_ARCHIVE_URL}"'
echo 'AGAVE_JOB_OWNER="\${AGAVE_JOB_OWNER}"'
echo 'AGAVE_JOB_TENANT="\${AGAVE_JOB_TENANT}"'
echo 'AGAVE_JOB_ARCHIVE="\${AGAVE_JOB_ARCHIVE}"'
echo 'AGAVE_JOB_MAX_RUNTIME="\${AGAVE_JOB_MAX_RUNTIME}"'
echo 'AGAVE_JOB_MAX_RUNTIME_SECONDS="\${AGAVE_JOB_MAX_RUNTIME_SECONDS}"'
echo 'AGAVE_JOB_MAX_RUNTIME_MILLISECONDS="\${AGAVE_JOB_MAX_RUNTIME_MILLISECONDS}"'
echo 'AGAVE_BASE_URL="\${AGAVE_BASE_URL}"'
echo 'AGAVE_JOB_ARCHIVE="\${AGAVE_JOB_ARCHIVE}"'
echo 'AGAVE_CACHE_DIR="\${AGAVE_CACHE_DIR}"'
echo 'AGAVE_JOB_ACCESS_TOKEN="\${AGAVE_JOB_ACCESS_TOKEN}"'
echo 'AGAVE_JOB_REFRESH_TOKEN="\${AGAVE_JOB_REFRESH_TOKEN}"'
echo 'AGAVE_JOB_PACKAGE_OUTPUT="\${AGAVE_JOB_PACKAGE_OUTPUT}"'
echo 'AGAVE_JOB_COMPRESS_OUTPUT="\${AGAVE_JOB_COMPRESS_OUTPUT}"'

echo "##################################################"
echo "# Job Runtime Environment "
echo "##################################################"
echo "\n"

LD_LIBRARY_PATH=/usr/local/lib 

# print environment
env

# copy to file for usage later on
env > ./environment.out

# resolve our job request parameters in funwave's input file
cp -f funwave-input.tpl  input.txt

sed -i 's#%WID%#\${WID}#' input.txt
sed -i 's#%AMP%#\${AMP}#' input.txt

# run our funwave command
mpirun -np 2 /home/jovyan/FUNWAVE-TVD/src/funwave_vessel 

# if the job request set the parameter compress_ouput to true
# the folder will be compressed
if [[ -z "\${compress_output}" ]]; then 
    tar czf output.tgz output
fi

""")


Writing file `funwave-wrapper.txt'

Using Agave commands, we make a directory on the storage server an deploy our wrapper file there.


In [4]:
!files-mkdir -S ${AGAVE_STORAGE_SYSTEM_ID} -N funwave-${AGAVE_APP_DEPLOYMENT_PATH}
!files-upload -F funwave-wrapper.txt -S ${AGAVE_STORAGE_SYSTEM_ID} funwave-${AGAVE_APP_DEPLOYMENT_PATH}/
!files-upload -F funwave-input.tpl -S ${AGAVE_STORAGE_SYSTEM_ID} funwave-${AGAVE_APP_DEPLOYMENT_PATH}/


Successfully created folder funwave-agave-deployment
Uploading funwave-wrapper.txt...
######################################################################## 100.0%
Uploading funwave-input.tpl...
######################################################################## 100.0%

All agave applications require a test file. The test file is a free form text file which allows you to specify what resources you might need to test your application.


In [5]:
writefile("funwave-test.txt","""
compress_output=1
AMP=2.0
WID=24.0
funwave-wrapper.txt
""")


Writing file `funwave-test.txt'

In [6]:
!files-mkdir -S ${AGAVE_STORAGE_SYSTEM_ID} -N funwave-${AGAVE_APP_DEPLOYMENT_PATH}
!files-upload -F funwave-test.txt -S ${AGAVE_STORAGE_SYSTEM_ID} funwave-${AGAVE_APP_DEPLOYMENT_PATH}/


Successfully created folder funwave-agave-deployment
Uploading funwave-test.txt...
######################################################################## 100.0%

More descriptive apps

We are recycling our previous app description here with a few changes. First, we are updating the app id so a new app will be created. Second we have added three new parameters.

  • compress_output is a boolean parameter that tells the wrapper whether to compress the output folder after running.
  • AMP is a numeric parameter specifying the wave amplitude. Notice the validator requires this to be a decimal value.
  • WID is a numeric parameter specifying the width. Notice the validator requires this to be a decimal value.

We have also removed the data file input from the previous app description. This is because we uploaded the input template with our app description, so it will be copied in and dynamically crated based on the runtime variable values every time the app is run.


In [7]:
writefile("funwave-app.txt","""
{  
   "name":"${AGAVE_USERNAME}-${MACHINE_NAME}-funwave",
   "version":"1.0",
   "label":"Runs a command",
   "shortDescription":"Runs a command",
   "longDescription":"",
   "deploymentSystem":"${AGAVE_STORAGE_SYSTEM_ID}",
   "deploymentPath":"funwave-${AGAVE_APP_DEPLOYMENT_PATH}",
   "templatePath":"funwave-wrapper.txt",
   "testPath":"funwave-test.txt",
   "executionSystem":"${AGAVE_EXECUTION_SYSTEM_ID}",
   "executionType":"CLI",
   "parallelism":"SERIAL",
   "modules":[],
   "inputs":[],
   "parameters":[{
     "id" : "compress_output",
     "value" : {
       "visible":true,
       "required":true,
       "type":"bool",
       "order":0,
       "enquote":false,
       "default":true
     },
     "details":{
         "label": "Compress output folder",
         "description": "If true, output will be packed and compressed",
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     },
     "semantics":{
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     }
   },
   {
     "id" : "AMP",
     "value" : {
       "visible":true,
       "required":true,
       "type":"string",
       "order":0,
       "enquote":false,
       "default":"3.0",
       "validator": "\\\\d+\\\\.\\\\d+"
     },
     "details":{
         "label": "Wave amplitude",
         "description": "Wave amplitude expressed as a decimal value",
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     },
     "semantics":{
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     }
   },
   {
     "id" : "WID",
     "value" : {
       "visible":true,
       "required":true,
       "type":"string",
       "order":0,
       "enquote":false,
       "default":"25.0",
       "validator": "\\\\d+\\\\.\\\\d+"
     },
     "details":{
         "label": "Width",
         "description": "Width expressed as a decimal value",
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     },
     "semantics":{
         "argument": null,
         "showArgument": false,
         "repeatArgument": false
     }
   }],
   "outputs":[]
}
""")


Writing file `funwave-app.txt'

In [8]:
!apps-addupdate -F funwave-app.txt


Successfully added app stevenrbrandt-sandbox-funwave-1.0

Running Jobs

We have registered a new Agave app to run our funwave code. Let's update our job definition to test it out. For fun, let's post our notifications to Slack. If you do not have access to a Slack channel where you can create an incoming webhook, use the previous requestbin url from the job request file below.


In [9]:
setvar("""
EVENT=*
WEBHOOK_URL=https://hooks.slack.com/services/
WEBHOOK_URL=${REQUESTBIN_URL}?name=\\\${JOB_NAME}&event=\${EVENT}&jobid=\\\${JOB_ID}
""")


EVENT=*
WEBHOOK_URL=https://hooks.slack.com/services/
WEBHOOK_URL=https://requestbin.agaveapi.co/1131s6o1?name=\${JOB_NAME}&event=${EVENT}&jobid=\${JOB_ID}

In [13]:
writefile("funwave-job.txt","""
 {
   "name":"funwave-1",
   "appId": "${AGAVE_USERNAME}-${MACHINE_NAME}-funwave-1.0",
   "executionSystem": "${AGAVE_EXECUTION_SYSTEM_ID}",
   "maxRunTime":"00:10:00",
   "archive": false,
   "notifications": [
    {
      "url":"${WEBHOOK_URL}",
      "event":"*",
      "persistent":"true"
    }
   ],
   "parameters": {
     "compress_output":true,
     "AMP":"4.0",
     "WID":"20.0"
   }
 }
""")


Writing file `funwave-job.txt'

Because the setvar() command can evalute $() style bash shell substitutions, we will use it to submit our job. This will capture the output of the submit command, and allow us to parse it for the JOB_ID. We'll use the JOB_ID in several subsequent steps.


In [14]:
setvar("""
# Capture the output of the job submit command
OUTPUT=$(jobs-submit -F funwave-job.txt)
# Parse out the job id from the output
JOB_ID=$(echo $OUTPUT | cut -d' ' -f4)
""")


OUTPUT=Successfully submitted job 4436216878533373465-242ac11b-0001-007
JOB_ID=4436216878533373465-242ac11b-0001-007

Job Monitoring and Output

While the job is running, the requestbin you registered will receive webhooks from Agave every time a job event occurs. To monitor this in real time, evaluate the next cell an visit the printed url in your browser:


In [15]:
!echo ${REQUESTBIN_URL}?inspect


https://requestbin.agaveapi.co/1131s6o1?inspect

Of course, you can also monitor the job status by polling. Note that the notifications you receive via email and webhook are less wasteful of resources. However, we show you this for completeness.


In [16]:
for iter in range(20):
    setvar("STAT=$(jobs-status $JOB_ID)")
    stat = os.environ["STAT"]
    sleep(5.0)
    if stat == "FINISHED" or stat == "FAILED":
        break


STAT=STAGED
STAT=STAGED
STAT=SUBMITTING
STAT=SUBMITTING
STAT=SUBMITTING
STAT=SUBMITTING
STAT=RUNNING
STAT=RUNNING
STAT=RUNNING
STAT=RUNNING
STAT=FINISHED

The jobs-history command provides you a record of the steps of what your job did. If your job fails for some reason, this is your best diagnostic.


In [17]:
!echo jobs-history ${JOB_ID}
!jobs-history ${JOB_ID}


jobs-history 4436216878533373465-242ac11b-0001-007
Job accepted and queued for submission.
Skipping staging. No input data associated with this job.
Preparing job for submission.
Attempt 1 to submit job
Fetching app assets from agave://nectar-storage-stevenrbrandt/funwave-agave-deployment
Staging runtime assets to agave://nectar-execstevenrbrandt//home/jovyan/stevenrbrandt/job-4436216878533373465-242ac11b-0001-007-funwave-1
CLI job successfully forked as process id 4839
CLI job successfully forked as process id 4839
Job receieved duplicate RUNNING notification
Job completed execution
Job completed. Skipping archiving at user request.

This command shows you the job id's and status of the last 5 jobs you ran.


In [18]:
!jobs-list -l 5


4436216878533373465-242ac11b-0001-007 FINISHED
7597476498183155225-242ac11b-0001-007 FINISHED
5360771817640956391-242ac11b-0001-007 FINISHED
4296939754503082471-242ac11b-0001-007 FINISHED
799296640238743065-242ac11b-0001-007 FINISHED

This next command provides you with a list of all the files generated by your job. You can use it to figure out which files you want to retrieve with jobs-output-get.


In [19]:
!jobs-output-list --rich --filter=type,length,name ${JOB_ID}


| type | length | name                |
| ---- | ------ | ----                |
| file | 87     | .agave.archive      |
| file | 399    | .agave.log          |
| file | 621    | environment.out     |
| file | 0      | funwave-1.err       |
| file | 4702   | funwave-1.ipcexe    |
| file | 7980   | funwave-1.out       |
| file | 5      | funwave-1.pid       |
| file | 1756   | funwave-input.tpl   |
| file | 54     | funwave-test.txt    |
| file | 2456   | funwave-wrapper.txt |
| file | 108    | Grid_Range.out      |
| file | 1753   | input.txt           |
| file | 6561   | LOG.txt             |
| dir  | 4096   | output              |
| file | 265    | time_dt.out         |

Retrieve the standard output.


In [20]:
!jobs-output-get ${JOB_ID} funwave-1.out
!cat funwave-1.out


######################################################################## 100.0%
Mon Nov 13 12:26:25 UTC 2017
##################################################
# Agave Job Runtime Variables 
##################################################


AGAVE_JOB_NAME="funwave-1"
AGAVE_JOB_ID="4436216878533373465-242ac11b-0001-007"
AGAVE_JOB_APP_ID="stevenrbrandt-sandbox-funwave-1.0"
AGAVE_JOB_EXECUTION_SYSTEM="nectar-execstevenrbrandt"
AGAVE_JOB_BATCH_QUEUE="none"
AGAVE_JOB_SUBMIT_TIME="2017-11-13T06:25:43.000-06:00"
AGAVE_JOB_ARCHIVE_SYSTEM="data.agaveapi.co"
AGAVE_JOB_ARCHIVE_PATH="stevenrbrandt/archive/jobs/job-4436216878533373465-242ac11b-0001-007"
AGAVE_JOB_NODE_COUNT="1"
AGAVE_JOB_PROCESSORS_PER_NODE="1"
AGAVE_JOB_MEMORY_PER_NODE="1.0"
AGAVE_JOB_ARCHIVE_URL=""
AGAVE_JOB_OWNER="stevenrbrandt"
AGAVE_JOB_TENANT="agave.prod"
AGAVE_JOB_ARCHIVE=""
AGAVE_JOB_MAX_RUNTIME="00:10:00"
AGAVE_JOB_MAX_RUNTIME_SECONDS="600.0"
AGAVE_JOB_MAX_RUNTIME_MILLISECONDS="600000"
AGAVE_BASE_URL="https://public.agaveapi.co/"
AGAVE_JOB_ARCHIVE=""
AGAVE_CACHE_DIR="${AGAVE_CACHE_DIR}"
AGAVE_JOB_ACCESS_TOKEN="${AGAVE_JOB_ACCESS_TOKEN}"
AGAVE_JOB_REFRESH_TOKEN="${AGAVE_JOB_REFRESH_TOKEN}"
AGAVE_JOB_PACKAGE_OUTPUT="${AGAVE_JOB_PACKAGE_OUTPUT}"
AGAVE_JOB_COMPRESS_OUTPUT="${AGAVE_JOB_COMPRESS_OUTPUT}"
##################################################
# Job Runtime Environment 
##################################################


SHELL=/bin/bash
TERM=dumb
SSH_CLIENT=127.0.0.1 51762 22
OLDPWD=/home/jovyan/stevenrbrandt/job-4436216878533373465-242ac11b-0001-007-funwave-1
SSH_TTY=/dev/pts/1
USER=jovyan
LS_COLORS=
LD_LIBRARY_PATH=/usr/local/lib
PATH=/home/jovyan/bin:/home/jovyan/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
MAIL=/var/mail/jovyan
PWD=/home/jovyan/stevenrbrandt/job-4436216878533373465-242ac11b-0001-007-funwave-1
HOME=/home/jovyan
SHLVL=2
LOGNAME=jovyan
SSH_CONNECTION=127.0.0.1 51762 127.0.0.1 22
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/env
 BATHY_CORRECTION DOES NOT EXIST. USE DEFAULT VALUE
 INI_UVZ DOES NOT EXIST. USE DEFAULT VALUE
 WaterLevel DOES NOT EXIST. USE DEFAULT VALUE
 ETA_LIMITER DOES NOT EXIST. USE DEFAULT VALUE
 EqualEnergy DOES NOT EXIST. USE DEFAULT VALUE
 PERIODIC DOES NOT EXIST. USE DEFAULT VALUE
 DIFFUSION_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 DIRECT_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 FRICTION_SPONGE DOES NOT EXIST. USE DEFAULT VALUE
 OBSTACLE_FILE DOES NOT EXIST. USE DEFAULT VALUE
 BREAKWATER_FILE DOES NOT EXIST. USE DEFAULT VALUE
 DISPERSION DOES NOT EXIST. USE DEFAULT VALUE
         DISPERSION Default:  DISPERSION
 Gamma1 DOES NOT EXIST. USE DEFAULT VALUE
        Gamma1 Default:  1.0: DISPERSION
 Gamma2 DOES NOT EXIST. USE DEFAULT VALUE
              Gamma2 Default:  1.0: Full nonlinear
 Beta_ref DOES NOT EXIST. USE DEFAULT VALUE
               Beta_ref Default:  -0.531
 Gamma3 DOES NOT EXIST. USE DEFAULT VALUE
                      Gamma3 Default:  1.0: NOT fully linear
 VISCOSITY_BREAKING DOES NOT EXIST. USE DEFAULT VALUE
                   VISCOSITY_BREAKING Default:  SWE Breaking
 SWE_ETA_DEP DOES NOT EXIST. USE DEFAULT VALUE
               SWE_ETA_DEP Default:  0.8
 Friction_Matrix DOES NOT EXIST. USE DEFAULT VALUE
             Friction_Matrix Default:  constant Cd
 Cd DOES NOT EXIST. USE DEFAULT VALUE
                  Cd_fixed Default:  0.0
 Time_Scheme DOES NOT EXIST. USE DEFAULT VALUE
       Time_Scheme Default:  Runge_Kutta
 CONSTRUCTION DOES NOT EXIST. USE DEFAULT VALUE
 HIGH_ORDER DOES NOT EXIST. USE DEFAULT VALUE
  HIGH_ORDER                     NOT DEFINED, USE FOURTH-ORDER
 CFL DOES NOT EXIST. USE DEFAULT VALUE
                       CFL Default:  0.5
 DT_fixed DOES NOT EXIST. USE DEFAULT VALUE
 FroudeCap DOES NOT EXIST. USE DEFAULT VALUE
                 FroudeCap Default:  3.0
 MinDepth DOES NOT EXIST. USE DEFAULT VALUE
                MinDepth Default:  0.1 m
 MinDepthFrc DOES NOT EXIST. USE DEFAULT VALUE
             MinDepthFrc Default:  0.1 m
 SHOW_BREAKING DOES NOT EXIST. USE DEFAULT VALUE
            SHOW_BREAKING Default:  TRUE
 Cbrk1 DOES NOT EXIST. USE DEFAULT VALUE
                    Cbrk1 Default:  0.65
 Cbrk2 DOES NOT EXIST. USE DEFAULT VALUE
                    Cbrk2 Default:  0.35
 WAVEMAKER_Cbrk DOES NOT EXIST. USE DEFAULT VALUE
            WAVEMAKER_Cbrk Default:  1.0
 WAVEMAKER_VIS DOES NOT EXIST. USE DEFAULT VALUE
           WAVEMAKER_VIS Default:  FALSE
 T_INTV_mean DOES NOT EXIST. USE DEFAULT VALUE
             T_INTV_mean Default:  LARGE
 STEADY_TIME DOES NOT EXIST. USE DEFAULT VALUE
             STEADY_TIME Default:  LARGE
 C_smg DOES NOT EXIST. USE DEFAULT VALUE
                     C_smg Default:  0.0
 nu_bkg DOES NOT EXIST. USE DEFAULT VALUE
                    nu_bkg Default:  0.0
 FIELD_IO_TYPE DOES NOT EXIST. USE DEFAULT VALUE
 NumberStations DOES NOT EXIST. USE DEFAULT VALUE
 OUTPUT_RES DOES NOT EXIST. USE DEFAULT VALUE
         OUTPUT_RES NOT FOUND, OUTPUT_RES=1: full resolution
 DEPTH_OUT DOES NOT EXIST. USE DEFAULT VALUE
 Hmax DOES NOT EXIST. USE DEFAULT VALUE
 Hmin DOES NOT EXIST. USE DEFAULT VALUE
 Umax DOES NOT EXIST. USE DEFAULT VALUE
 MFmax DOES NOT EXIST. USE DEFAULT VALUE
 VORmax DOES NOT EXIST. USE DEFAULT VALUE
 MASK DOES NOT EXIST. USE DEFAULT VALUE
 MASK9 DOES NOT EXIST. USE DEFAULT VALUE
 Umean DOES NOT EXIST. USE DEFAULT VALUE
 Vmean DOES NOT EXIST. USE DEFAULT VALUE
 ETAmean DOES NOT EXIST. USE DEFAULT VALUE
 WaveHeight DOES NOT EXIST. USE DEFAULT VALUE
 SXL DOES NOT EXIST. USE DEFAULT VALUE
 SXR DOES NOT EXIST. USE DEFAULT VALUE
 SYL DOES NOT EXIST. USE DEFAULT VALUE
 SYR DOES NOT EXIST. USE DEFAULT VALUE
 SourceX DOES NOT EXIST. USE DEFAULT VALUE
 SourceY DOES NOT EXIST. USE DEFAULT VALUE
 P DOES NOT EXIST. USE DEFAULT VALUE
 Q DOES NOT EXIST. USE DEFAULT VALUE
 Fx DOES NOT EXIST. USE DEFAULT VALUE
 Fy DOES NOT EXIST. USE DEFAULT VALUE
 Gx DOES NOT EXIST. USE DEFAULT VALUE
 Gy DOES NOT EXIST. USE DEFAULT VALUE
 AGE DOES NOT EXIST. USE DEFAULT VALUE
 OUT_NU DOES NOT EXIST. USE DEFAULT VALUE
 TMP DOES NOT EXIST. USE DEFAULT VALUE
      EtaBlowVal Default:  100xmax_depth
 ----------------- STATISTICS ----------------
  TIME        DT
  0.4266E-01  0.4266E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.2583E+04  0.1254E+08  0.3995E+01 -0.4316E-06  0.5200E-01  0.5199E-01
  MaxTotalU   PhaseS      Froude 
  0.5200E-01  0.1090E+02  0.4771E-02
   PRINTING FILE NO.     1  TIME/TOTAL:        0.043 /       4.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.1022E+01  0.4249E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.2569E+04  0.1254E+08  0.2451E+01 -0.1729E-05  0.9724E+00  0.9720E+00
  MaxTotalU   PhaseS      Froude 
  0.9739E+00  0.1069E+02  0.9108E-01
   PRINTING FILE NO.     2  TIME/TOTAL:        1.022 /       4.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.2005E+01  0.4317E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.2542E+04  0.1253E+08  0.9894E+00 -0.2243E-05  0.1206E+01  0.1201E+01
  MaxTotalU   PhaseS      Froude 
  0.1210E+01  0.1035E+02  0.1168E+00
   PRINTING FILE NO.     3  TIME/TOTAL:        2.005 /       4.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.3012E+01  0.4431E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.2520E+04  0.1253E+08  0.9698E+00 -0.1168E+01  0.9685E+00  0.9088E+00
  MaxTotalU   PhaseS      Froude 
  0.9715E+00  0.1029E+02  0.9437E-01
   PRINTING FILE NO.     4  TIME/TOTAL:        3.012 /       4.000
 ----------------- STATISTICS ----------------
  TIME        DT
  0.4041E+01  0.4515E-01
  MassVolume  Energy      MaxEta      MinEta      Max U       Max V 
  0.2516E+04  0.1253E+08  0.1367E+01 -0.1401E+01  0.7978E+00  0.5050E+00
  MaxTotalU   PhaseS      Froude 
  0.7997E+00  0.1027E+02  0.7790E-01
   PRINTING FILE NO.     5  TIME/TOTAL:        4.041 /       4.000
 Simulation takes   21.010228826999082      seconds
 Normal Termination!

Check our resolved wrapper template to verify the variables were replaced.


In [21]:
!jobs-output-get ${JOB_ID} funwave-1.ipcexe
!cat funwave-1.ipcexe


######################################################################## 100.0%
#!/bin/bash 

############################################################## 
# Agave Runtime IO Redirections 
############################################################## 

# Capture the PID of this job on the system for remote monitoring 
echo $$ > funwave-1.pid 

# Pause for 2 seconds to avoid a callback race condition 
sleep 2 

# Redirect STDERR and STDOUT to the custom job output and error files 
exec 2>funwave-1.err 1>funwave-1.out 


##########################################################
# Agave Environment Settings 
##########################################################

# Ensure we're in the job work directory 
cd /home/jovyan/stevenrbrandt/job-4436216878533373465-242ac11b-0001-007-funwave-1

# Location of agave job lifecycle log file 
AGAVE_LOG_FILE=/home/jovyan/stevenrbrandt/job-4436216878533373465-242ac11b-0001-007-funwave-1/.agave.log


##########################################################
# Agave Utility functions 
##########################################################

# cross-plaltform function to print an ISO8601 formatted timestamp 
function agave_datetime_iso() { 
  date '+%Y-%m-%dT%H:%M:%S%z'; 
} 

# standard logging function to write agave job lifecycle logs
function agave_log_response() { 
  echo "[$(agave_datetime_iso)] ${@}"; 
} 2>&1 >> "${AGAVE_LOG_FILE}"

# Callback to signal the job has started executing user-defined logic
agave_log_response $(curl -sSk "https://public.agaveapi.co/jobs/v2/trigger/job/4436216878533373465-242ac11b-0001-007/token/fb872e11-50d5-45c7-a8cf-31527ef2d837/status/RUNNING?filter=id,status" 2>&1) 


##########################################################
# Agave App and System Environment Settings 
##########################################################

# No modules commands configured for this app

# No custom environment variables configured for this app


##########################################################
# Begin App Wrapper Template Logic 
##########################################################

#!/bin/bash
# This is a generic wrapper script for checking the runtime environment
# of a job and verifying the runtime template variable values
set +x

date

# print out the agave runtiem variables
echo "##################################################"
echo "# Agave Job Runtime Variables "
echo "##################################################"
echo "
"
echo 'AGAVE_JOB_NAME="funwave-1"'
echo 'AGAVE_JOB_ID="4436216878533373465-242ac11b-0001-007"'
echo 'AGAVE_JOB_APP_ID="stevenrbrandt-sandbox-funwave-1.0"'
echo 'AGAVE_JOB_EXECUTION_SYSTEM="nectar-execstevenrbrandt"'
echo 'AGAVE_JOB_BATCH_QUEUE="none"'
echo 'AGAVE_JOB_SUBMIT_TIME="2017-11-13T06:25:43.000-06:00"'
echo 'AGAVE_JOB_ARCHIVE_SYSTEM="data.agaveapi.co"'
echo 'AGAVE_JOB_ARCHIVE_PATH="stevenrbrandt/archive/jobs/job-4436216878533373465-242ac11b-0001-007"'
echo 'AGAVE_JOB_NODE_COUNT="1"'
echo 'AGAVE_JOB_PROCESSORS_PER_NODE="1"'
echo 'AGAVE_JOB_MEMORY_PER_NODE="1.0"'
echo 'AGAVE_JOB_ARCHIVE_URL=""'
echo 'AGAVE_JOB_OWNER="stevenrbrandt"'
echo 'AGAVE_JOB_TENANT="agave.prod"'
echo 'AGAVE_JOB_ARCHIVE=""'
echo 'AGAVE_JOB_MAX_RUNTIME="00:10:00"'
echo 'AGAVE_JOB_MAX_RUNTIME_SECONDS="600.0"'
echo 'AGAVE_JOB_MAX_RUNTIME_MILLISECONDS="600000"'
echo 'AGAVE_BASE_URL="https://public.agaveapi.co/"'
echo 'AGAVE_JOB_ARCHIVE=""'
echo 'AGAVE_CACHE_DIR="${AGAVE_CACHE_DIR}"'
echo 'AGAVE_JOB_ACCESS_TOKEN="${AGAVE_JOB_ACCESS_TOKEN}"'
echo 'AGAVE_JOB_REFRESH_TOKEN="${AGAVE_JOB_REFRESH_TOKEN}"'
echo 'AGAVE_JOB_PACKAGE_OUTPUT="${AGAVE_JOB_PACKAGE_OUTPUT}"'
echo 'AGAVE_JOB_COMPRESS_OUTPUT="${AGAVE_JOB_COMPRESS_OUTPUT}"'

echo "##################################################"
echo "# Job Runtime Environment "
echo "##################################################"
echo "
"

LD_LIBRARY_PATH=/usr/local/lib 

# print environment
env

# copy to file for usage later on
env > ./environment.out

# resolve our job request parameters in funwave's input file
cp -f funwave-input.tpl  input.txt

sed -i 's#%WID%#20.0#' input.txt
sed -i 's#%AMP%#4.0#' input.txt

# run our funwave command
mpirun -np 2 /home/jovyan/FUNWAVE-TVD/src/funwave_vessel 

# if the job request set the parameter compress_ouput to true
# the folder will be compressed
if [[ -z "1" ]]; then 
    tar czf output.tgz output
fi


##########################################################
# End App Wrapper Template Logic 
##########################################################

# Callback to signal the job has completed all user-defined logic
agave_log_response $(curl -sSk "https://public.agaveapi.co/jobs/v2/trigger/job/4436216878533373465-242ac11b-0001-007/token/fb872e11-50d5-45c7-a8cf-31527ef2d837/status/CLEANING_UP?filter=id,status" 2>&1) 


Check the input.txt file resolved from the input template with our runtime values


In [22]:
!jobs-output-get ${JOB_ID} input.txt
!cat input.txt


######################################################################## 100.0%
!INPUT FILE FOR FUNWAVE_TVD
  ! NOTE: all input parameter are capital sensitive
  ! --------------------TITLE-------------------------------------
  ! title only for log file
TITLE = VESSEL
  ! -------------------HOT START---------------------------------
HOT_START = F
FileNumber_HOTSTART = 1
  ! -------------------PARALLEL INFO-----------------------------
  ! 
  !    PX,PY - processor numbers in X and Y
  !    NOTE: make sure consistency with mpirun -np n (px*py)
  !    
PX = 2
PY = 1
  ! --------------------DEPTH-------------------------------------
  ! Depth types, DEPTH_TYPE=DATA: from depth file
  !              DEPTH_TYPE=FLAT: idealized flat, need depth_flat
  !              DEPTH_TYPE=SLOPE: idealized slope, 
  !                                 need slope,SLP starting point, Xslp
  !                                 and depth_flat
DEPTH_TYPE = FLAT
DEPTH_FLAT = 10.0
  ! -------------------PRINT---------------------------------
  ! PRINT*,
  ! result folder
RESULT_FOLDER = output/

  ! ------------------DIMENSION-----------------------------
  ! global grid dimension
Mglob = 500
Nglob = 100

  ! ----------------- TIME----------------------------------
  ! time: total computational time/ plot time / screen interval 
  ! all in seconds
TOTAL_TIME = 4.0
PLOT_INTV = 1.0
PLOT_INTV_STATION = 50000.0
SCREEN_INTV = 1.0
HOTSTART_INTV = 360000000000.0

WAVEMAKER = INI_GAU
AMP = 4.0
Xc = 250.0
Yc = 50.0
WID = 20.0

  ! -----------------GRID----------------------------------
  ! if use spherical grid, in decimal degrees
  ! cartesian grid sizes
DX = 1.0
DY = 1.0
  ! ----------------SHIP WAKES ----------------------------
VESSEL_FOLDER = ./
NumVessel = 2
  ! -----------------OUTPUT-----------------------------
ETA = T
U = T
V = T

Retrieve the standard error output.


In [23]:
!jobs-output-get ${JOB_ID} funwave-1.err
!cat funwave-1.err



In this next example, we run a job using an application created by the person sitting next to you. Simply edit the value for AGAVE_FRIEND


In [24]:
setvar("AGAVE_FRIEND=training001")


AGAVE_FRIEND=training001

In [28]:
!systems-roles-list ${AGAVE_EXECUTION_SYSTEM_ID}


stevenrbrandt OWNER
training002 USER

In [30]:
!systems-roles-addupdate -u ${AGAVE_FRIEND} -r PUBLISHER ${AGAVE_EXECUTION_SYSTEM_ID}


Successfully updated roles for user training001 on nectar-execstevenrbrandt

In [31]:
!systems-roles-list ${AGAVE_EXECUTION_SYSTEM_ID}


stevenrbrandt OWNER
training001 PUBLISHER
training002 USER

At this point you should be able to do the following:

  • Create an app that runs on your friend's execution system
  • Put a containerized code on your friend's execution system using the techniques in the docker and singularity section
  • Run your containerized job on your friend's exection system

In [ ]: